<?php

/**
 * 模板类
 *
 */

class Template {
  var $var_regexp = "\@?\\\$[a-zA-Z_][\\\$\w]*(?:\[[\w\-\.\"\'\[\]\$]+\])*";
  var $vtag_regexp = "\<\?php echo (\@?\\\$[a-zA-Z_][\\\$\w]*(?:\[[\w\-\.\"\'\[\]\$]+\])*)\;\?\>";
  var $const_regexp = "\{([A-Z_]+)\}";
  private $config = array();

  function __construct($config=array()) {
    $this->config['theme']    = "templates/default/";
    $this->config['cache']    = "caches/themes/default/";
    $this->config['auto']     = true;
    $this->config['time']     = 0;
    $this->config['autopath'] = 1;
    $this->config['repath']   = false;
    $this->setconfig($config);
  }

  function __destruct() {

  }

  function setconfig($config=array()) {
    if (!empty($config) && is_array($config)){
      foreach($config as $key=>$value) {
        $this->config[$key] = $value;
      }
    }
  }

  function setrepath($v) {
    $this->config['repath'] = $v;
  }

  function cache($file) {
    $tplfile = $this->config['theme'].$file;
    $md5data = md5_file($tplfile);
    $expireTime = time();
    $template = file_get_contents($tplfile);
    $template = $this->parse($template);
    $template = "<?php !defined('FSDKP') && exit('Access Denied'); ?>\r\n" .
                "<?php C('Template')->check('$file','$md5data',$expireTime); ?>\r\n" .
                $template;

    if($this->config['repath']) $cacheFile = $this->config['cache'].'autopath_'.$file.'.php';
    else $cacheFile = $this->config['cache'].$file.'.php';

    if ($this->makepath($cacheFile) !== true) {
      exit('can\'t create cache');
    }
    file_put_contents($cacheFile, $template);
    return $template;
  }

  function getfile($file) {
    if($this->config['repath']) $cacheFile = $this->config['cache'].'autopath_'.$file.'.php';
    else $cacheFile = $this->config['cache'].$file.'.php';
    !file_exists($cacheFile) && $this->cache($file);
    return realpath($cacheFile);
  }

  function getcontent($file) {
    return file_get_contents($this->getfile($file));
  }

  function check($file, $md5data, $expireTime) {
    if ($this->config['auto'] && md5_file($this->config['theme'].$file) != $md5data)
      $this->cache($file);
    if ($this->config['time'] != 0 && (time() - $expireTime >= $this->config['time'] * 60))
      $this->cache($file);
  }

  function parse($template) {

    //解析路径
    if($this->config['autopath']) {
      $template = preg_replace("/\<([^\>]*?\shref=)\"(.+?)\"(.*?)>/ise", "\$this->srchref('\\1','\\2','\\3')", $template);
      $template = preg_replace("/\<([^\>]*?\ssrc=)\"(.+?)\"(.*?)>/ise", "\$this->srchref('\\1','\\2','\\3')", $template);
    }

    $template = preg_replace("/\<\!\-\-\{(.+?)\}\-\-\>/s", "{\\1}", $template);//去除html注释符号<!--{}-->
    $template = preg_replace("/\{($this->var_regexp)\}/", "<?php echo \\1;?>", $template);//替换带{}的变量
    $template = preg_replace("/\{($this->const_regexp)\}/", "<?php echo \\1;?>", $template);//替换带{}的常量
    $template = preg_replace("/(?<!\<\?php echo |\\\\)$this->var_regexp/", "<?php echo \\0;?>", $template);//替换重复的?php echo
    $template = preg_replace("/\{php (.*?)\}/ies", "\$this->stripvTag('<?php \\1?>')", $template);//替换php标签
    $template = preg_replace("/\{echo (.*?)\}/ies", "\$this->stripvTag('<?php echo \\1;?>')", $template);//替换echo标签
    $template = preg_replace("/\{for (.*?)\}/ies", "\$this->stripvTag('<?php for(\\1) {?>')", $template);//替换for标签
    $template = preg_replace("/\{elseif\s+(.+?)\}/ies", "\$this->stripvTag('<?php } elseif (\\1) { ?>')", $template);//替换elseif标签
    for($i=0; $i<3; $i++) {
      $template = preg_replace("/\{loop\s+$this->vtag_regexp\s+$this->vtag_regexp\s+$this->vtag_regexp\}(.+?)\{\/loop\}/ies", "\$this->loopSection('\\1', '\\2', '\\3', '\\4')", $template);
      $template = preg_replace("/\{loop\s+$this->vtag_regexp\s+$this->vtag_regexp\}(.+?)\{\/loop\}/ies", "\$this->loopSection('\\1', '', '\\2', '\\3')", $template);
    }
    $template = preg_replace("/\{if\s+(.+?)\}/ies", "\$this->stripvTag('<?php if(\\1) { ?>')", $template);//替换if标签
    $template = preg_replace("/\{include\s+(.*?)\}/is", "<?php include \\1; ?>", $template);//替换include标签
    $template = preg_replace("/\{template\s+([^\s]+?)\}/is", "<?php include T('\\1'); ?>", $template);//替换template标签
    $template = preg_replace("/\{else\}/is", "<?php } else { ?>", $template);//替换else标签
    $template = preg_replace("/\{\/if\}/is", "<?php } ?>", $template);//替换/if标签
    $template = preg_replace("/\{\/for\}/is", "<?php } ?>", $template);//替换/for标签
    
    $template = preg_replace("/\{lang\s+(.+?)\}/ies", "\$this->stripvTag('<?php echo L(\"\\1\"); ?>')", $template);//语言包
    $template = preg_replace("/\{data\s+(.+?)\}/ies", "\$this->stripvTag('<?php echo D(\"\\1\"); ?>')", $template);
        
    $template = preg_replace("/$this->const_regexp/", "<?php echo \\1;?>", $template);//常量
    $template = preg_replace("/(\\\$[a-zA-Z_]\w+\[)([a-zA-Z_]\w+)\]/i", "\\1'\\2']", $template);//将二维数组替换成带单引号的标准模式
    
    return $template;
  }


  function srchref($a,$b,$c) {
    $pre = str_replace(APP_ROOT,'',$this->config['theme']);
    if($this->config['repath']) $pre = '../'.$pre;
    if (preg_match("/^(\.|\/|\?|#|\{|http:|https:|mailto:|tencent:|javascript:|svn:)/i",$b)) {
      return str_replace("\\\"", "\"", "<$a\"$b\"$c>");
    }
    else {
      return str_replace("\\\"", "\"", "<$a\"".$pre."$b\"$c>");
    }
  }

  function stripvTag($s) {
    return preg_replace("/$this->vtag_regexp/is", "\\1", str_replace("\\\"", '"', $s));
  }

  function stripTagQuotes($expr) {
    $expr = preg_replace("/\<\?php echo (\\\$.+?);\?\>/s", "{\\1}", $expr);
    $expr = str_replace("\\\"", "\"", preg_replace("/\[\'([a-zA-Z0-9_\-\.\x7f-\xff]+)\'\]/s", "[\\1]", $expr));
    return $expr;
  }

  function loopSection($arr, $k, $v, $statement) {
    $arr = $this->stripvTag($arr);
    $k = $this->stripvTag($k);
    $v = $this->stripvTag($v);
    $statement = str_replace("\\\"", '"', $statement);
    return $k ? "<?php foreach((array)$arr as $k=>$v) {?>$statement<?php }?>" : "<?php foreach((array)$arr as $v) {?>$statement<?php } ?>";
  }

  function makepath($path) {
    $dirs = explode('/', dirname($path));
    $tmp = '';
    foreach ($dirs as $dir) {
      $tmp .= $dir . '/';
      if (!file_exists($tmp) && !@mkdir($tmp, 0777))
        return $tmp;
    }
    return true;
  }

}

?>